﻿
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace DropboxLib
{
    public class OAuth
    {
        private readonly OAuthBase _oAuthBase;

        public OAuth()
        {
            _oAuthBase = new OAuthBase();
        }

        public async Task<OAuthToken> GetRequestToken(Uri baseUri, string consumerKey, string consumerSecret)
        {

            var uri = new Uri(baseUri, "oauth/request_token");

            uri = SignRequest(uri, consumerKey, consumerSecret);

            var request = (HttpWebRequest)WebRequest.Create(uri);
            request.Method = "GET";

            var response = await request.GetResponseAsync();

            var queryString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            var parts = queryString.Split('&');
            var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
            var secret = parts[0].Substring(parts[0].IndexOf('=') + 1);

            return new OAuthToken(token, secret);


            //var uri = new Uri(baseUri, "oauth/request_token");
            //OAuthBase oAuth = new OAuthBase();
            //string nonce = oAuth.GenerateNonce();
            //string timeStamp = oAuth.GenerateTimeStamp();
            //string parameters;
            //string normalizedUrl;
            //string signature = oAuth.GenerateSignature(uri, consumerKey, consumerSecret,
            //    String.Empty, String.Empty, "GET", timeStamp, nonce, OAuthBase.SignatureTypes.HMACSHA1,
            //    out normalizedUrl, out parameters);

            //signature = HttpUtility.UrlEncode(signature);

            //StringBuilder requestUri = new StringBuilder(Constants.DROPBOX_URI_REQTOKEN.ToString());
            //requestUri.AppendFormat("?oauth_consumer_key={0}&", Constants.DROPBOX_CONSUMER_KEY);
            //requestUri.AppendFormat("oauth_nonce={0}&", nonce);
            //requestUri.AppendFormat("oauth_timestamp={0}&", timeStamp);
            //requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
            //requestUri.AppendFormat("oauth_version={0}&", "1.0");
            //requestUri.AppendFormat("oauth_signature={0}", signature);

            //var request = (HttpWebRequest)WebRequest.Create(new Uri(requestUri.ToString()));
            //request.Method = "GET";

            //var response = await request.GetResponseAsync();
            //var queryString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            //var parts = queryString.Split('&');
            //var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
            //var tokenSecret = parts[0].Substring(parts[0].IndexOf('=') + 1);

            //return new OAuthToken(token, tokenSecret);
        }

        public async Task<OAuthToken> GetAccessToken(Uri baseUri, string consumerKey, string consumerSecret, OAuthToken requestToken)
        {

            var uri = new Uri(baseUri, "oauth/access_token");

            uri = SignRequest(uri, consumerKey, consumerSecret, requestToken);

            var request = (HttpWebRequest)WebRequest.Create(uri);
            request.Method = "GET";

            var response = await request.GetResponseAsync();
            var reader = new StreamReader(response.GetResponseStream());
            var accessToken = reader.ReadToEnd();

            var parts = accessToken.Split('&');
            var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
            var secret = parts[0].Substring(parts[0].IndexOf('=') + 1);

            return new OAuthToken(token, secret);


            //var uri = new Uri(baseUri, "oauth/access_token");

            //OAuthBase oAuth = new OAuthBase();

            //var nonce = oAuth.GenerateNonce();
            //var timeStamp = oAuth.GenerateTimeStamp();
            //string parameters;
            //string normalizedUrl;
            //var signature = oAuth.GenerateSignature(uri, consumerKey, consumerSecret,
            //    requestToken.Token, requestToken.Secret, "GET", timeStamp, nonce,
            //    OAuthBase.SignatureTypes.HMACSHA1, out normalizedUrl, out parameters);

            //signature = HttpUtility.UrlEncode(signature);

            //var requestUri = new StringBuilder(uri);
            //requestUri.AppendFormat("?oauth_consumer_key={0}&", Constants.DROPBOX_CONSUMER_KEY);
            //requestUri.AppendFormat("oauth_token={0}&", requestToken.Token);
            //requestUri.AppendFormat("oauth_nonce={0}&", nonce);
            //requestUri.AppendFormat("oauth_timestamp={0}&", timeStamp);
            //requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
            //requestUri.AppendFormat("oauth_version={0}&", "1.0");
            //requestUri.AppendFormat("oauth_signature={0}", signature);

            //var request = (HttpWebRequest)WebRequest.Create(requestUri.ToString());
            //request.Method = "GET";

            //var response = await request.GetResponseAsync();
            //var reader = new StreamReader(response.GetResponseStream());
            //var accessToken = reader.ReadToEnd();

            //var parts = accessToken.Split('&');
            //var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
            //var secret = parts[0].Substring(parts[0].IndexOf('=') + 1);

            //// close reader to avoid memory leaks.
            //reader.Close();

            //return new OAuthToken(token, secret);
        }

        public Uri SignRequest(Uri uri, string consumerKey, string consumerSecret, OAuthToken token = null)
        {
            var nonce = _oAuthBase.GenerateNonce();
            var timestamp = _oAuthBase.GenerateTimeStamp();
            string parameters;
            string normalizedUrl;

            string requestToken = token == null ? String.Empty : token.Token;
            string tokenSecret = token == null ? String.Empty : token.Secret;

            var signature = _oAuthBase.GenerateSignature(
                uri, consumerKey, consumerSecret,
                requestToken, tokenSecret, "GET", timestamp,
                nonce, OAuthBase.SignatureTypes.HMACSHA1,
                out normalizedUrl, out parameters);

            signature = HttpUtility.UrlEncode(signature);

            var requestUri = new StringBuilder(uri.ToString());
            requestUri.AppendFormat("?oauth_consumer_key={0}&", consumerKey);
            if (!String.IsNullOrEmpty(requestToken))
                requestUri.AppendFormat("oauth_token={0}&", requestToken);
            requestUri.AppendFormat("oauth_nonce={0}&", nonce);
            requestUri.AppendFormat("oauth_timestamp={0}&", timestamp);
            requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
            requestUri.AppendFormat("oauth_version={0}&", "1.0");
            requestUri.AppendFormat("oauth_signature={0}", signature);

            return new Uri(requestUri.ToString());
        }

        public Uri SignRequest(Uri uri, string consumerKey, string consumerSecret, OAuthToken token, string httpMethod)
        {
            var nonce = _oAuthBase.GenerateNonce();
            var timestamp = _oAuthBase.GenerateTimeStamp();
            string parameters;
            string normalizedUrl;

            string requestToken = token == null ? String.Empty : token.Token;
            string tokenSecret = token == null ? String.Empty : token.Secret;

            var signature = _oAuthBase.GenerateSignature(
                uri, consumerKey, consumerSecret,
                requestToken, tokenSecret, httpMethod, timestamp,
                nonce, OAuthBase.SignatureTypes.HMACSHA1,
                out normalizedUrl, out parameters);

            var requestUri = String.Format("{0}?{1}&oauth_signature={2}",
                normalizedUrl, parameters, HttpUtility.UrlEncode(signature));

            return new Uri(requestUri);
        }

    }
}
